package com.ljx.video.util;

import com.j256.simplemagic.ContentInfo;
import com.j256.simplemagic.ContentInfoUtil;
import com.ljx.video.constant.MyConstant;
import com.ljx.video.domain.vo.req.FileUploadReq;
import com.ljx.video.exception.ApiException;
import io.minio.*;
import io.minio.messages.DeleteError;
import io.minio.messages.DeleteObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @Author: LiJunXi
 * @Description:
 * @Date: 2025-01-18  00:27
 */
@Component
public class MinioUtil {

    @Autowired
    private MinioClient minioClient;

    @Value("${oss.minio.bucketName}")
    private String bucketName;

    public void uploadChunkToMinio(FileUploadReq req){
        try {
            uploadToMinio(getChunkFilePath(req.getFileMd5(), req.getChunk()), new ByteArrayInputStream(req.getFile().getBytes()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public void uploadM3u8ToMinio(InputStream inputStream, String fileMd5) {
        try {
            uploadToMinio(getM3u8FilePath(fileMd5), inputStream);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void uploadToMinio(String objectName, InputStream inputStream){
        try {
            PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                    .object(objectName)
                    .bucket(bucketName)
                    .stream(inputStream, inputStream.available(), -1)
                    .build();
            minioClient.putObject(putObjectArgs);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public String getMimeType(String extension) {
        if (Objects.isNull(extension)){
            extension = "";
        }
        ContentInfo extensionMatch = ContentInfoUtil.findExtensionMatch(extension);
        String mimeType = MediaType.APPLICATION_OCTET_STREAM_VALUE;  // 通用mimeType，字节流
        if (Objects.nonNull(extensionMatch)){
            mimeType = extensionMatch.getMimeType();
        }
        return mimeType;
    }

    private String getChunkFilePath(String fileMd5, Long chunk){
        return "chunks/" + fileMd5 + "/" + chunk;
    }

    private String getTempFilePath(String fileMd5, String extension){
        return "files_temp/" + fileMd5 + "." + extension;
    }

    private String getM3u8FilePath(String fileMd5){
        return "video_m3u8/" + fileMd5 + "/video.m3u8";
    }

    private String getM3u8TsFilePath(String fileMd5, int i) {
        return "video_m3u8/" + fileMd5 + "/" + i + ".m3u8";
    }

    public ComposeSource getComposeSourceByChunk(String fileMd5, Long i) {
        try {
            return ComposeSource.builder()
                    .bucket(bucketName)
                    .object(getChunkFilePath(fileMd5, i))
                    .build();
        } catch (Exception e) {
            throw new ApiException("获取分片文件出错");
        }
    }

    public void mergeComposeSource(String filename, String fileMd5, List<ComposeSource> composeSourceList) {
        String extension = FileUtil.getFileExtension(filename);
        try {
            minioClient.composeObject(
                    ComposeObjectArgs.builder()
                            .bucket(bucketName)
                            .object(getTempFilePath(fileMd5, extension))
                            .sources(composeSourceList)
                            .build()
            );
        } catch (Exception e) {
            e.printStackTrace();
            throw new ApiException("合并分片出错");
        }
    }

    public void clearChunks(Long chunkTotal, String fileMd5) {
        List<DeleteObject> deleteObjects = new ArrayList<>();
        try {
            for (int i = 0; i < chunkTotal; i++){
                deleteObjects.add(new DeleteObject(getChunkFilePath(fileMd5, Long.parseLong(String.valueOf(i)))));
            }
            RemoveObjectsArgs removeObjectsArgs = RemoveObjectsArgs.builder()
                    .bucket(bucketName)
                    .objects(deleteObjects)
                    .build();
            // 删除
            Iterable<Result<DeleteError>> results = minioClient.removeObjects(removeObjectsArgs);
            // 检验是否已经删除
            for (Result<DeleteError> result : results) {
                DeleteError deleteObject = null;
                try {
                    deleteObject = result.get();
                } catch (Exception e) {
                    throw new ApiException("清除分片失败");
                }
            }
        } catch (Exception e){
            throw new ApiException("获取对象出错");
        }
    }

    public InputStream getVideoStream(String fileMd5, String filename) {
        String extension = FileUtil.getFileExtension(filename);
        try {
            GetObjectArgs getObjectArgs = GetObjectArgs.builder()
                    .bucket(bucketName)
                    .object(getTempFilePath(fileMd5, extension))
                    .build();
            return minioClient.getObject(getObjectArgs);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public void uploadM3u8TsToMinio(InputStream inputStream, String fileMd5, int index) {
        uploadToMinio(getM3u8TsFilePath(fileMd5, index), inputStream);
    }

    public Path createTempFile(String s) {
        try {
            Path directoryPath = Paths.get(s);
            if (!Files.exists(directoryPath)) {
                Files.createDirectories(directoryPath);
            }
            return directoryPath;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
